package com.kingsoft.dc.khaos.util

import com.kingsoft.dc.khaos.KhaosConf
import com.kingsoft.dc.khaos.metadata.{Dependency, EdgeInfo, ModuleCommon}
import org.json4s.DefaultFormats

import scala.collection.immutable.List
import scala.collection.mutable.ListBuffer
import org.json4s._
import org.json4s.jackson.JsonMethods._

import scala.collection.mutable

/**
  * Created by chengguangqing on 2019/5/31.
  */
class AppConfigParse(conf: KhaosConf) extends Logging{
  /**
    * 解析程序输入的json信息
    *
    * @param json : 传入json配置信息
    * @return : 返回job的前端配置
    */

  def parseJson(json: String): (String, String, String,String, List[ModuleCommon]) = {

    val commonEnv = mutable.HashMap[String,String]()

    implicit val formats = DefaultFormats
    val parser = parse(json, true)

    val id = (parser \ "id").extract[String]
    val name = (parser \ "name").extract[String]
    val runEnv=(parser \ "run_env").extract[String]

    val priority = try {
      (parser \ "dispatch" \ "priority").extract[String]
    } catch {
      case ex: Exception => "1"
    }

    val dispatchTime = try {
      (parser \ "dispatch" \ "time").extract[String]
    } catch {
      case ex: Exception =>
        log.error("Cannot Find Dispatch Time!")
        ""
    }

    val widgets = (parser \ "graph" \ "widgets")
    val edges = (parser \ "graph" \ "edges")

    //nodeList 获取所有组件的ID
    val nodeValues = (parser \ "graph" \ "widgets" \ "id").values
    val nodeList = nodeValues.asInstanceOf[List[String]]//.map{id => BigInt(id)}

    //khaosInfo 存放ModuleCommon
    val khaosInfo = new ListBuffer[ModuleCommon]

    //relationList 存放边的关系
    var relationList = List[(EdgeInfo, EdgeInfo)]()

    edges.asInstanceOf[JArray].children.foreach { jv =>
      val source = (jv \ "source").extract[EdgeInfo]
      val destination = (jv \ "destination").extract[EdgeInfo]
      relationList +:= (source, destination)
    }

    //存放出度degreeOut和入度信息degreeIn
    //将data 依赖也弄出来了，留了个口子，没有全部放到moduleCommon中
    var degreeDataOut = Map[String, List[Dependency]]()
    var degreeDataIn = Map[String, List[Dependency]]()

    var degreeIn = Map[String, List[String]]()
    var degreeOut = Map[String, List[String]]()

    relationList.foreach { r =>
      val list = degreeDataOut.getOrElse(r._1.node, Nil)
      degreeDataOut += (r._1.node ->
        list.+:(new Dependency(r._1.node, r._1.seq, r._2.node, r._2.seq)))
      val list2 = degreeOut.getOrElse(r._1.node, Nil)
      degreeOut += (r._1.node -> list2.+:(r._2.node))

      val listIn = degreeDataIn.getOrElse(r._2.node, Nil)
      degreeDataIn += (r._2.node ->
        listIn.+:(new Dependency(r._1.node, r._1.seq, r._2.node, r._2.seq)))
      val list3 = degreeIn.getOrElse(r._2.node, Nil)
      degreeIn += (r._2.node -> list3.+:(r._1.node))
    }


    nodeList.foreach { node =>
      if (degreeOut.get(node.toString).isEmpty) {
        degreeOut += (node.toString -> Nil)
      }
      if (degreeDataOut.get(node.toString).isEmpty) {
        degreeDataOut += (node.toString -> Nil)
      }
      if (degreeIn.get(node.toString).isEmpty) {
        degreeIn += (node.toString -> Nil)
      }
      if (degreeDataIn.get(node.toString).isEmpty) {
        degreeDataIn += (node.toString -> Nil)
      }
    }

    //最后将ModuleCommon  放入dittoInfo中 list[ModuleCommon]
    widgets.children.foreach { modConf =>
      val modConfMap = modConf.values.asInstanceOf[Map[String, _]]
      val mid = String.valueOf(modConfMap.get("id").get)
      val mname = String.valueOf(modConfMap.get("name").get)
      val engine = String.valueOf(modConfMap.get("engine").get)
      val clazz = String.valueOf(modConfMap.get("clazz").get)
      val clazzType = String.valueOf(modConfMap.get("clazz_type").get)
      val moduleConf = compact(render(modConf)) //输出json字符串

      conf.set(mid, moduleConf)

      val module = new ModuleCommon(
        mid,
        mname,
        engine,
        clazz,
        clazzType,
        moduleConf,
        dispatchTime,
        degreeIn.getOrElse(mid, Nil),
        degreeDataIn.getOrElse(mid, Nil),
        degreeOut.getOrElse(mid, Nil),
        degreeDataOut.getOrElse(mid,Nil)
      )
      khaosInfo += module
    }
    (id, name, priority, runEnv,khaosInfo.toList)
  }
}
